use crate::{
    app_error::AppError, app_writer::{AppResult, AppWriter, ErrorResponseBuilder}, dtos::user::{
        UserAddRequest, UserLoginRequest, UserLoginResponse, UserResponse, UserUpdateRequest,
    }, services::user
};
use crate::app_writer::ResponseBuilder;
use salvo::Writer;
use salvo::{
    http::cookie::Cookie,
    oapi::{
        endpoint,
        extract::{JsonBody, PathParam},
    },
    Depot, Request, Response,
};
use validator::Validate;

use super::get_userid_from_jwt;

#[endpoint(tags("comm"))]
pub async fn post_login(req: JsonBody<UserLoginRequest>, res: &mut Response) {
    let result: AppResult<UserLoginResponse> = user::login(req.0).await;
    match result {
        Ok(data) => {
            let jwt_token = data.token;
            let cookie = Cookie::build(("jwt_token", jwt_token.clone()))
                .path("/")
                .http_only(true)
                .build();
            res.add_cookie(cookie);
            ResponseBuilder::with_data(jwt_token).into_response(res);
        }
        Err(e) => ErrorResponseBuilder::with_err(e).into_response(res),
    }
}

#[endpoint(tags("users"))]
pub async fn post_add_user(new_user: JsonBody<UserAddRequest>) -> AppResult<AppWriter<UserResponse>> {
    new_user.0.validate()?;
    let result = user::add_user(new_user.0).await;
    let result = AppWriter(result);
    Ok(result)
}

#[endpoint(tags("users"))]
pub async fn put_update_user(req: &mut Request) -> AppResult<AppWriter<UserResponse>> {
    let req: UserUpdateRequest = req.extract().await?;
    let result = user::update_user(req).await;
    Ok(AppWriter(result))
}

#[endpoint(tags("users"))]
pub async fn delete_user(id: PathParam<String>, depot: &mut Depot) -> AppResult<()> {
    let user_id =  get_userid_from_jwt(depot)?;
    if user_id == id.0 {
        Err(AppError::BadRequest("Cannot delete yourself"))
    } else {
        let _ = user::delete_user(id.0).await?;
        Ok(())
    }
}

#[endpoint(tags("users"))]
pub async fn get_users() -> AppWriter<Vec<UserResponse>> {
    let result = user::users().await;
    AppWriter(result)
}

#[endpoint(tags("users"))]
pub async fn get_whoami(depot: &mut Depot) -> AppResult<AppWriter<UserResponse>> {
    let user_id = get_userid_from_jwt(depot)?;
    let res = user::get_user(user_id.to_string()).await?;
    let res = AppWriter(Ok(res));
    Ok(res)
}
